package com.changanw.ratelimiter.aspectj;

import com.changanw.ratelimiter.annotation.RateLimiter;
import com.changanw.ratelimiter.enums.LimitType;
import com.changanw.ratelimiter.exception.RateLimitException;
import com.changanw.ratelimiter.utils.IpUtils;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.Collections;

@Aspect
@Component
public class RateLimitAspect {
    private static final Logger logger = LoggerFactory.getLogger(RateLimitAspect.class);
    @Autowired
    RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    RedisScript<Long> redisScript;
    @Before("@annotation(rateLimiter)")
    public void before(JoinPoint jp, RateLimiter rateLimiter) throws RateLimitException {
        int time = rateLimiter.time();
        int count = rateLimiter.count();
        String comeKey = getCombKey(rateLimiter,jp);
        try {
            Long number = redisTemplate.execute(redisScript, Collections.singletonList(comeKey),time,count);
            if (number == null || number.intValue() > count){
                logger.info("达到最大限流");
                throw new RateLimitException("请求过于频繁");
            }
            logger.info("一个时间窗内的请求次数{},当前请求次数{},缓存的key为{}",count,number,comeKey);

        }catch (Exception e){
            throw e;
        }

    }

    /**
     * 这个key 是接口的调用次数的缓存， 缓存在redis 的key
     * rate_limit:11.11.11.11-com.changanw.controller.hellocontroller-hello(ip 包，方法)
     * rate_limit:com.changanw.controller.hellocontroller-hello(ip 包，方法)
     * @param rateLimiter
     * @param jp
     * @return
     */
    private String getCombKey(RateLimiter rateLimiter, JoinPoint jp) {
        StringBuffer key = new StringBuffer(rateLimiter.key());
        if (rateLimiter.limitType() == LimitType.IP){
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            key.append(IpUtils.getIpAddr(request))
                    .append("-");
        }
        final MethodSignature signature = (MethodSignature) jp.getSignature();
        final Method method = signature.getMethod();
        key.append(method.getDeclaringClass())
                .append("-")
                .append(method.getName());
        return key.toString();
    }
}
